package com.ccp.dev.workflow.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.util.*;
import com.ccp.dev.workflow.dao.ActDefModelDao;
import com.ccp.dev.workflow.dao.BpmNodeButtonDao;
import com.ccp.dev.workflow.model.*;
import org.dom4j.Document;
import org.dom4j.Element;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.xml.bind.JAXBException;
import java.util.*;

/**
 * ClassDescribe:
 * 对象功能:自定义工具条 服务类
 *
 * @author :wangcheng
 * Date: 2019-06-17
 */
@Service
public class BpmNodeButtonService extends BaseService<BpmNodeButton> {
    @Resource
    private BpmNodeButtonDao bpmNodeButtonDao;
    @Resource
    private ActDefModelDao actDefModelDao;

    /**
     * 初始化流程的全部按钮
     *
     * @param modelId 流程定义id
     */
    @Transactional(rollbackFor = Exception.class)
    public void initAll(String modelId) throws Exception {
        ActDefModel model = actDefModelDao.getById(modelId);
        String procDefId = model.getProcDefId();
        try {
            bpmNodeButtonDao.delByModelId(procDefId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        List<BpmButton> buttons = getBpmButtons();
        if (BeanUtils.isEmpty(buttons)) {
            return;
        }
        // 起始表单按钮
        initStartForm(procDefId, modelId, buttons);
        // 获取流程节点
        Map<String, FlowNodeInfo> flowNodeInfoMap = NodeCache.getByProcDefId(procDefId);

        Set<Map.Entry<String, FlowNodeInfo>> flowNodeSet = flowNodeInfoMap.entrySet();
        for (Map.Entry<String, FlowNodeInfo> entry : flowNodeSet) {
            FlowNodeInfo flowNode = entry.getValue();
            boolean isSignTask = flowNode.getIsSignNode();
            boolean isFirstNode = flowNode.getIsFirstNode();
            // 节点按钮。
            if (!StringPool.START_NODE_NAME.equalsIgnoreCase(flowNode.getNodeId())) {
                initNodeId(procDefId, modelId, entry.getKey(), isSignTask, isFirstNode, buttons);
            }
        }
    }

    /**
     * 初始化按钮
     *
     * @param modelId 模型id
     * @param nodeId  节点id
     */
    @Transactional(rollbackFor = Exception.class)
    public void init(String modelId, String nodeId) throws Exception {
        ActDefModel actDefModel = actDefModelDao.getById(modelId);
        String procDefId = actDefModel.getProcDefId();
        // 读取button.xml
        List<BpmButton> bpmButtons = getBpmButtons();
        if (BeanUtils.isEmpty(bpmButtons)) {
            return;
        }
        try {
            // 是否是起始表单
            if (StringUtil.isEmpty(nodeId)) {
                bpmNodeButtonDao.delByStartForm(procDefId);
                initStartForm(procDefId, modelId, bpmButtons);
            } else {
                Map<String, Object> map = new HashMap<>(2);
                map.put("procDefId", procDefId);
                map.put("nodeId", nodeId);
                bpmNodeButtonDao.delByNodeId(map);
                boolean isSignTask = NodeCache.isSignTaskNode(procDefId, nodeId);
                boolean isFirstNode = NodeCache.isFirstNode(procDefId, nodeId);
                initNodeId(procDefId, modelId, nodeId, isSignTask, isFirstNode, bpmButtons);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


    }

    /**
     * 从buttons.xml中读取按钮
     *
     * @return 按钮列表
     * @throws JAXBException 转换异常
     */
    private List<BpmButton> getBpmButtons() throws Exception {
        // 读button.xml
        String buttonPath = StringPool.SLASH + StringPool.BUTTON_FILE;
        String xml = FileUtil.readFile(buttonPath);
        Document document = Dom4jUtil.loadXml(xml);
        Element root = document.getRootElement();
        String xmlStr = root.asXML();
        BpmNodeButtonXml bpmButtonList = (BpmNodeButtonXml) XmlBeanUtil.unmarshall(xmlStr, BpmNodeButtonXml.class);
        return bpmButtonList.getButtons();
    }


    /**
     * 初始化起始节点
     *
     * @param procDefId 流程定义id
     * @param modelId   模型id
     */
    private void initStartForm(String procDefId, String modelId, List<BpmButton> list) {
        for (BpmButton button : list) {
            if (0 == button.getType() && 1 == button.getInit()) {
                try {
                    bpmNodeButtonDao.add(new BpmNodeButton(procDefId, modelId, button.getText(), button.getOperatortype()));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 初始化其它节点(不是起始节点)
     *
     * @param procDefId   流程定义id
     * @param modelId     流程模型id
     * @param nodeId      节点id
     * @param isSignTask  是否是会签任务
     * @param isFirstNode 是否是起始节点
     */
    private void initNodeId(String procDefId, String modelId, String nodeId,
                            boolean isSignTask, boolean isFirstNode, List<BpmButton> list) {
        int nodeType = isSignTask ? 1 : 0;
        try {
            //是否第一个节点
            if (isFirstNode) {
                for (BpmButton button : list) {
                    if (1 == button.getType() && 1 == button.getInit()) {
                        bpmNodeButtonDao.add(new BpmNodeButton(procDefId, modelId, nodeId, button.getText(), button.getOperatortype(), nodeType));
                    }
                }
            } else {
                if (isSignTask) {
                    for (BpmButton button : list) {
                        if ((2 == button.getType() || 4 == button.getType()) && 1 == button.getInit()) {
                            bpmNodeButtonDao.add(new BpmNodeButton(procDefId, modelId, nodeId, button.getText(), button.getOperatortype(), nodeType));
                        }
                    }
                } else {
                    for (BpmButton button : list) {
                        if ((3 == button.getType() || 4 == button.getType()) && 1 == button.getInit()) {
                            bpmNodeButtonDao.add(new BpmNodeButton(procDefId, modelId, nodeId, button.getText(), button.getOperatortype(), nodeType));
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过流程定义id 获取流程节点按钮信息
     *
     * @param procDefId 流程定义id
     * @return 流程节点按钮信息
     */
    public Map<String, List<BpmNodeButton>> getMapByProcDefId(String procDefId) {
        List<BpmNodeButton> bpmNodeButtonList = bpmNodeButtonDao.queryByProcDefId(procDefId);
        Map<String, List<BpmNodeButton>> nodeButtonMap = new HashMap<>(16);
        if (BeanUtils.isEmpty(bpmNodeButtonList)) {
            return nodeButtonMap;
        }

        for (BpmNodeButton bpmNodeButton : bpmNodeButtonList) {
            if (bpmNodeButton.getIsstartform() == 1) {
                addItem(nodeButtonMap, bpmNodeButton, "start");
            } else {
                addItem(nodeButtonMap, bpmNodeButton, bpmNodeButton.getNodeid());
            }
        }
        return nodeButtonMap;
    }

    /**
     * 添加操作按钮到集合中
     *
     * @param map           节点按钮map
     * @param bpmNodeButton 节点按钮
     * @param key           标识
     */
    private void addItem(Map<String, List<BpmNodeButton>> map, BpmNodeButton bpmNodeButton, String key) {
        if (map.containsKey(key)) {
            map.get(key).add(bpmNodeButton);
        } else {
            List<BpmNodeButton> list = new ArrayList<>();
            list.add(bpmNodeButton);
            map.put(key, list);
        }
    }

    /**
     * 根据流程定义ID删除按钮——清除按钮配置
     *
     * @param modelId 流程定义ID  （据此获取procDefId）
     */
    @Transactional(rollbackFor = Exception.class)
    public void delByDefId(String modelId) {
        ActDefModel actDefModel = actDefModelDao.getById(modelId);
        String procDefId = actDefModel.getProcDefId();
        try {
            bpmNodeButtonDao.delByDefId(procDefId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 删除接口
     *
     * @param modelId 流程定义ID
     * @param nodeId  流程节点ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void deByDefNodeId(String modelId, String nodeId) {
        ActDefModel actDefModel = actDefModelDao.getById(modelId);
        String procDefId = actDefModel.getProcDefId();
        try {
            if (StringUtil.isEmpty(nodeId)) {
                bpmNodeButtonDao.delByStartForm(procDefId);
            } else {
                Map<String, Object> map = new HashMap<>(2);
                map.put("procDefId", procDefId);
                map.put("nodeId", nodeId);
                bpmNodeButtonDao.delByNodeId(map);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据流程定义ID获取起始表单的操作按钮
     *
     * @param procDefId 流程定义ID
     * @return 操作按钮
     */
    public List<BpmNodeButton> getByStartForm(String procDefId) {
        return bpmNodeButtonDao.getByStartForm(procDefId);
    }

    /**
     * 获取流程定义的按钮。
     *
     * @param procDefId 流程定义id
     * @return 节点按钮map
     */
    public Map<String, List<BpmNodeButton>> getMapByStartForm(String procDefId) {
        Map<String, List<BpmNodeButton>> map = new HashMap<>(16);
        List<BpmNodeButton> list = bpmNodeButtonDao.getByStartForm(procDefId);
        if (BeanUtils.isEmpty(list)) {
            return map;
        }
        for (BpmNodeButton bpmNodeButton : list) {
            addItem(map, bpmNodeButton, "button");
        }
        return map;
    }

    /**
     * 根据流程定义ID和流程节点ID获取按钮。
     *
     * @param procDefId 流程定义id。
     * @param nodeId    流程节点id。
     * @return 节点按钮信息
     */
    public Map<String, List<BpmNodeButton>> getMapByDefNodeId(String procDefId, String nodeId) {
        Map<String, List<BpmNodeButton>> map = new HashMap<>(16);
        List<BpmNodeButton> list = this.getByDefNodeId(procDefId, nodeId);
        if (BeanUtils.isEmpty(list)) {
            return map;
        }
        for (BpmNodeButton bpmNodeButton : list) {
            addItem(map, bpmNodeButton, "button");
        }
        return map;
    }


    /**
     * 根据流程定义ID和节点ID获取操作按钮
     *
     * @param procDefId 流程定义ID
     * @param nodeId    流程节点ID
     * @return 操作按钮
     */
    public List<BpmNodeButton> getByDefNodeId(String procDefId, String nodeId) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("procDefId", procDefId);
        map.put("nodeId", nodeId);
        return bpmNodeButtonDao.getByDefNodeId(map);
    }

    /**
     * 保存排序
     *
     * @param ids 按钮id字符串
     */
    @Transactional(rollbackFor = Exception.class)
    public void sort(String[] aryId) {
//        String[] aryId = ids.split(",");
        for (int i = 0; i < aryId.length; i++) {
            Map<String, Object> params = new HashMap<>(2);
            //主键
            params.put("id", aryId[i]);
            //排序
            params.put("sn", (long) (i + 1));
            try {
                bpmNodeButtonDao.updSn(params);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 根据流程定义ID和节点操作类型判断是否已经存在
     *
     * @param bpmNodeButton 按钮操作
     * @return 操作类型是否存在
     */
    public boolean isOperatorExist(BpmNodeButton bpmNodeButton) {
        String procDefId = bpmNodeButton.getProcDefId();
        Integer operatortype = bpmNodeButton.getOperatortype();
        Map<String, Object> map = new HashMap<>(3);
        map.put("procDefId", procDefId);
        map.put("operatortype", operatortype);
        if (bpmNodeButton.getIsstartform() == 1) {
            return bpmNodeButtonDao.isStartFormExist(map) > 0;
        }
        String nodeId = bpmNodeButton.getNodeid();
        map.put("nodeId", nodeId);
        return bpmNodeButtonDao.isExistByNodeId(map) > 0;
    }

    /**
     * 更新按钮时 根据流程定义ID和节点操作类型判断是否已经存在
     *
     * @param bpmNodeButton 按钮对象
     * @return 操作类型是否存在
     */
    public boolean isOperatorExistForUpd(BpmNodeButton bpmNodeButton) {
        String procDefId = bpmNodeButton.getProcDefId();
        String id = bpmNodeButton.getId();
        Integer operatortype = bpmNodeButton.getOperatortype();
        Map<String, Object> map = new HashMap<>(3);
        map.put("procDefId", procDefId);
        map.put("id", id);
        map.put("operatortype", operatortype);
        if (bpmNodeButton.getIsstartform() == 1) {
            return bpmNodeButtonDao.isStartFormExistForUpd(map) > 0;
        }
        String nodeId = bpmNodeButton.getNodeid();
        map.put("nodeId", nodeId);
        return bpmNodeButtonDao.isExistByNodeIdForUpd(map) > 0;
    }

    /**
     * 获取操作按钮设置
     *
     * @param procDefId 流程定义id
     * @return 节点按钮列表
     */
    public List<BpmNodeButton> getByProcDefId(String procDefId) {
        return bpmNodeButtonDao.queryByProcDefId(procDefId);
    }
}
